package com.huanzhidadi.java8inaction.chapter4;

import com.alibaba.fastjson2.JSON;
import com.huanzhidadi.java8inaction.model.Dish;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 使用流
 */
@Slf4j
public class StreamUseTest {
    public static void main(String[] args) {
        List<Dish> menu = Arrays.asList(
                new Dish("pork", false, 800, Dish.Type.MEAT),
                new Dish("beef", false, 700, Dish.Type.MEAT),
                new Dish("season fruit", true, 120, Dish.Type.OTHER),
                new Dish("chicken", false, 400, Dish.Type.MEAT),
                new Dish("rice", true, 350, Dish.Type.OTHER),
                new Dish("pizza", true, 550, Dish.Type.OTHER),
                new Dish("prawns", false, 300, Dish.Type.FISH),
                new Dish("salmon", false, 450, Dish.Type.FISH)
        );

        // 用谓词筛选素食菜单 filter
        List<Dish> vegetarianMenu = menu.stream()
                .filter(Dish::isVegetarian)
                .collect(Collectors.toList());
        log.info(JSON.toJSONString(vegetarianMenu));
        System.out.println("-----------------------------------------");

        // 筛选各异的元素 distinct
        List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
        numbers.stream()
                .filter(i -> i % 2 == 0)
                .distinct()
                .forEach(System.out::println);
        System.out.println("-----------------------------------------");

        // 截短流 limit
        List<Dish> dishes = menu.stream()
                .filter(d -> d.getCalories() > 300)
                .limit(3)
                .collect(Collectors.toList());
        log.info(JSON.toJSONString(dishes));
        System.out.println("-----------------------------------------");

        // 跳过元素 skip
        List<Dish> dishesBySkip = menu.stream()
                .filter(d -> d.getCalories() > 300)
                .skip(2)
                .collect(Collectors.toList());
        log.info(JSON.toJSONString(dishesBySkip));
        System.out.println("-----------------------------------------");

        // 映射 map
        List<Integer> dishNameLengths = menu.stream()
                .map(Dish::getName)
                .map(String::length)
                .collect(Collectors.toList());
        log.info(JSON.toJSONString(dishNameLengths));
        System.out.println("-----------------------------------------");

        // map无法对集合元素生成的流进行整合
        List<String> words = Arrays.asList("Hello", "world");
        List<String[]> wordCollect = words.stream()
                // 将每个单词转换为由其字母构成的数组
                .map(word -> word.split(""))
                .distinct()
                .collect(Collectors.toList());
        log.info(JSON.toJSONString(wordCollect));
        System.out.println("-----------------------------------------");

        // 流的扁平化  flatMap
        List<String> wordFlatCollect = words.stream()
                // 将每个单词转换为由其字母构成的数组
                .map(word -> word.split(""))
                // 将各个生成流 扁平化为 单个流
                .flatMap(Arrays::stream)
                .distinct()
                .collect(Collectors.toList());
        log.info(JSON.toJSONString(wordFlatCollect));
        System.out.println("-----------------------------------------");

        // 给定两个数字列表，如何返回所有的数对？
        List<Integer> numbers1 = Arrays.asList(1, 2, 3);
        List<Integer> numbers2 = Arrays.asList(3, 4);
        List<int[]> pairs = numbers1.stream()
                .flatMap(i -> numbers2.stream()
                        .map(j -> new int[]{i, j})
                )
                .collect(Collectors.toList());
        log.info(JSON.toJSONString(pairs));
        System.out.println("-----------------------------------------");

        // 流中至少有一个元素能匹配给定的谓词 anyMatch
        if (menu.stream().anyMatch(Dish::isVegetarian)) {
            log.info("当前菜单适合素食者。");
            System.out.println("-----------------------------------------");
        }

        // 确定流中的元素都能匹配给定的谓词 allMatch
        if (menu.stream().allMatch(dish -> dish.getCalories() < 1000)) {
            log.info("当前菜单所有菜品的热量都低于1000卡路里。");
            System.out.println("-----------------------------------------");
        }

        // 返回流中的任意元素 findAny
        menu.stream()
                .filter(Dish::isVegetarian)
                .findAny()
                .ifPresent(d -> log.info(d.getName()));
        System.out.println("-----------------------------------------");

        // 查找第一个元素 findFirst
        List<Integer> someNumbers = Arrays.asList(1, 2, 3, 4, 5);
        someNumbers.stream()
                .map(x -> x*x)
                .filter(x -> x%3 == 0)
                .findFirst()
                .ifPresent(d -> log.info(d + ""));
        System.out.println("-----------------------------------------");

        // 归约 把一个流中的元素按照给定的规则组合起来 reduce
        List<Integer> reduceNumbers = Arrays.asList(1, 2, 3, 4, 5);

        // 元素求和
        Integer sum = reduceNumbers.stream()
                .reduce(0, (a, b) -> a + b);
        log.info(sum + "");
        System.out.println("-----------------------------------------");

        // 元素求积
        Integer product = reduceNumbers.stream()
                .reduce(1, (a, b) -> a * b);
        log.info(product + "");
        System.out.println("-----------------------------------------");

        // 最大值
        reduceNumbers.stream()
                .reduce(Integer::max)
                .ifPresent(d -> log.info(d + ""));
        System.out.println("-----------------------------------------");

    }
}
